#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <linux/videodev.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <sys/types.h>
#include <pthread.h>
#include <fcntl.h>
#include <time.h>

#include "../../capture.h"
#include "output_avi.h"
#include "encode.h"

static pthread_t worker;
static char * ARG_OUTPUTFILE="/home/cf/tmp/video.avi";

//extern GLOBALS global;
GLOBALS *pGlobal;
extern void *enc_handle; 


static void *worker_thread( void *arg ) {
    unsigned char *mp4_buffer = NULL;  
    unsigned char *in_buffer = NULL;      
  
    double enctime;  
    double totalenctime = 0.;  
    float totalPSNR[3] = {0., 0., 0.};  
  
    int totalsize;  
    int result;  
    int m4v_size;  
    int key;  
    int stats_type;  
    int stats_quant;  
    int stats_length;  
    int use_assembler = 1;  
  
    int input_num;  
//    int output_num;  
  
    //char filename[256];     
    FILE *out_file = NULL;  
  
    printf("xvid_encraw - raw mpeg4 bitstream encoder ");  
    printf("written by Christoph Lampert 2002-2003\n\n");  
  
    in_buffer = (unsigned char *) malloc(IMAGE_SIZE(XDIM, YDIM));  
    if (!in_buffer)  
        goto free_all_memory;  
  
    /* this should really be enough memory ! */  
    mp4_buffer = (unsigned char *) malloc(IMAGE_SIZE(XDIM, YDIM) * 2);  
    if (!mp4_buffer)  
        goto free_all_memory;  
    
    /***************************************************************************** 
     *                            XviD PART  Start 
     ****************************************************************************/  
  
  
    result = enc_init(use_assembler);  
    if (result) {  
        fprintf(stderr, "Encore INIT problem, return value %d\n", result);  
        goto release_all;  
    }  
  
    /***************************************************************************** 
     *                            Main loop 
     ****************************************************************************/  
  
    if (ARG_SAVEMPEGSTREAM && ARG_OUTPUTFILE) {  
  
        if ((out_file = fopen(ARG_OUTPUTFILE, "w+b")) == NULL) {  
            fprintf(stderr, "Error opening output file %s\n", ARG_OUTPUTFILE);  
            goto release_all;  
        }  
  
    } else {  
        out_file = NULL;  
    }  
  
    /***************************************************************************** 
     *                       Encoding loop 
     ****************************************************************************/  
  
    totalsize = 0;  
  
    result = 0;  
  
    input_num = 0;              /* input frame counter */  
    //output_num = 0;             /* output frame counter */  
  
    do {  
  
        char *type;  
        int sse[3];  
  
        if (input_num >= ARG_MAXFRAMENR) 
	{  
            result = 1;  
        }  
  
        if (!result) 
	{
            pthread_mutex_lock(&pGlobal->db);
            pthread_cond_wait(&pGlobal->db_update, &pGlobal->db);
            /* read buffer */
            memcpy(in_buffer, pGlobal->buf, pGlobal->bufSize);
            pthread_mutex_unlock( &pGlobal->db );
        }  
        /***************************************************************************** 
         *                       Encode and decode this frame 
         ****************************************************************************/  
  
        enctime = msecond();  
        m4v_size =  
            enc_main(!result ? in_buffer : 0, mp4_buffer, &key, &stats_type,  
                     &stats_quant, &stats_length, sse);  
        enctime = msecond() - enctime;  
  
        /* Write the Frame statistics */  
  
        printf("%5d: key=%i, time= %6.0f, len= %7d", !result ? input_num : -1,  
               key, (float) enctime, (int) m4v_size);  
  
        if (stats_type > 0) 
	{    /* !XVID_TYPE_NOTHING */  
              switch (stats_type) 
	      {  
            case XVID_TYPE_IVOP:  
                type = "I";  
                break;  
            case XVID_TYPE_PVOP:  
                type = "P";  
                break;  
            case XVID_TYPE_BVOP:  
                type = "B";  
                break;  
            case XVID_TYPE_SVOP:  
                type = "S";  
                break;  
            default:  
                type = "U";  
                break;  
	      }
          
  
	      printf(" | type=%s, quant= %2d, len= %7d", type, stats_quant,  
                   stats_length);  
	}
        printf("\n");  
  
        if (m4v_size < 0) 
	{  
            break;  
        }  
  
        /* Update encoding time stats */  
        totalenctime += enctime;  
        totalsize += m4v_size;  
  
        /***************************************************************************** 
         *                       Save stream to file 
         ****************************************************************************/  
  
        if (m4v_size > 0 && ARG_SAVEMPEGSTREAM) 
	{  
	    /* Save ES stream */  
            if (ARG_OUTPUTFILE && out_file)  
                fwrite(mp4_buffer, 1, m4v_size, out_file);  
        }  
        input_num++;  
    } while (!pGlobal->stopFlag);  
  
  
  
    /***************************************************************************** 
     *         Calculate totals and averages for output, print results 
     ****************************************************************************/  
  
    printf("Tot: enctime(ms) =%7.2f,               length(bytes) = %7d\n",  
           totalenctime, (int) totalsize);  
  
    if (input_num > 0) {  
        totalsize /= input_num;  
        totalenctime /= input_num;  
        totalPSNR[0] /= input_num;  
        totalPSNR[1] /= input_num;  
        totalPSNR[2] /= input_num;  
    } else {  
        totalsize = -1;  
        totalenctime = -1;  
    }  
  
    printf("Avg: enctime(ms) =%7.2f, fps =%7.2f, length(bytes) = %7d",  
           totalenctime, 1000 / totalenctime, (int) totalsize);  
    if (ARG_STATS) {  
        printf(", psnr y = %2.2f, psnr u = %2.2f, psnr v = %2.2f",  
               totalPSNR[0],totalPSNR[1],totalPSNR[2]);  
    }  
    printf("\n");  
  
  
    /***************************************************************************** 
     *                            XviD PART  Stop 
     ****************************************************************************/  
  
 release_all:    
    if (enc_handle) {  
        result = enc_stop();  
        if (result)  
            fprintf(stderr, "Encore RELEASE problem return value %d\n",  
                    result);  
    }  

    if (out_file)  
        fclose(out_file);  
  
 free_all_memory:      
    free(mp4_buffer);  
    free(in_buffer);  
  
    return ( (void*) 0);  
  
}  
  


int output_init(char *outputParam, void *pglobal) {
  pGlobal = (GLOBALS*) pglobal;
    if(0 == pGlobal->avi_mode )
    {
        fprintf(stderr, "can't use output avi mode without set avi_mode (./catpure -a / -avi)\n");
        exit(EXIT_FAILURE);
    }
    return 0;
}

int output_stop(void) {
    //pthread_cancel(worker);
  //等待线程退出
    int terr;
    void * tret;
    terr = pthread_join(worker, &tret);
    if(terr != 0)
    {
      perror("join thread input_yuyv worker_thread error!");
      exit(EXIT_FAILURE);
    }
  
    return 0;
}


int output_run(void) {    
    pthread_create(&worker, 0, worker_thread, NULL);
    
    //使用了 pthread_join， 固不再使用线程分离
    //pthread_detach(worker);
    return 0;
}
